#include "linux/interrupt.h"

#include "linux/stddef.h"

#include "linux/irq.h"
#include "linux/errno.h"
#include "linux/signal.h"
#include "i386/kernel/screen.h"

/*
 * disable an irq without waiting
 */
void disable_irq_nosync(u32 irq) {
  struct irq_desc* desc = irq_desc + irq;
  // u32 flags;
  if (!desc->depth++) {
    desc->status |= IRQ_DISABLED;
    desc->handler->disable(irq);
  }

  puts("Not Impl: disable_irq_nosync");
}

void disable_irq(u32 irq) {
  /*
  struct irq_desc* desc = irq_desc + irq;
  disable_irq_nosync(irq);
  if (desc->action) {
    synchronize_irq(irq);
  }
  */

  puts("Not Impl: disable_irq");
}

void enable_irq(u32 irq) {
  /*
  struct irq_desc* desc = irq_desc + irq;
  u32 flags;
  switch (desc->depth) {
    case 0:
      break;
    case 1: {
      u32 status = desc->status & ~IRQ_DISABLED;
      desc->status = status;
      if ((desc->status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
        desc->status = status | IRQ_REPLAY;
        hw_resend_irq(desc->handler, irq);
      }
      desc->handler->enable(irq);
    }
    default:
      desc->depth--;
  }
  */

  puts("Not Impl: enable_irq");
}

asmlinkage int setup_irq(u32 irq, struct irqaction* new) {
  struct irq_desc *desc = irq_desc + irq;
  struct irqaction *old, **p;
  // u32 flags;, for spinlock
  int shared = 0;
  if (desc->handler == &no_irq_type) {
    return -ENOSYS;
  }

  /* 判断是否采用了共享，
     1. 如果不共享，且之前已经设置了IRQ, 则返回 EBUSY
     2. 如果可以共享，那么放在desc链表的尾部
   */
  p = &desc->action;
  if ((old = *p) != NULL) {
    if (!(old->flags & new->flags & SA_SHIRQ)) {
      return -EBUSY;
    }

    /* action的链表的尾部，此处实际完成了对处理函数的设置 */
    do {
      p = &old->next;
      old = *p;
    } while (old);
    shared = 1;
  }
  *p = new;

  /* 在这里仅仅是打开的 IRQ0, 如何设置关联IRQ0与对应的中断处理函数呢 */
  if (!shared) {
    desc->depth = 0;
    desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT |
                      IRQ_WAITING | IRQ_INPROGRESS);
    if (desc->handler->startup) {
      desc->handler->startup(irq);
    } else {
      desc->handler->enable(irq);
    }
  }

  new->irq = irq;

  /*
  register_irg_proc(irq);
  new_dir = NULL;
  */
  
  // register_handler_proc(irq, new);

  return 0;
}
